// exception.cc 
//    Entry point into the Nachos kernel from user programs.
//    There are two kinds of things that can cause control to
//    transfer back to here from user code:
//
//    syscall -- The user code explicitly requests to call a procedure
//    in the Nachos kernel.  Right now, the only function we support is
//    "Halt".
//
//    exceptions -- The user code does something that the CPU can't handle.
//    For instance, accessing memory that doesn't exist, arithmetic errors,
//    etc.  
//
//    Interrupts (which can also cause control to transfer from user
//    code into the Nachos kernel) are handled elsewhere.
//
// For now, this only handles the Halt() system call.
// Everything else core dumps.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include <stdio.h>        // FA98
#include <stdlib.h>
#include "copyright.h"
#include "system.h"
#include "syscall.h"
#include "addrspace.h"   // FA98
#include "sysdep.h"   // FA98
#include "directory.h" 
#include "list.h"
#include <vector.h>
// begin FA98

static int SRead(int addr, int size, int id);
static void SWrite(char *buffer, int size, int id);
Thread * getID(int toGet);
void Parse(char *filename);
void InnerParse(char *);
void Cat(bool isCombine);





// end FA98

//----------------------------------------------------------------------
// ExceptionHandler
//     Entry point into the Nachos kernel.  Called when a user program
//    is executing, and either does a syscall, or generates an addressing
//    or arithmetic exception.
//
//     For system calls, the following is the calling convention:
//
//     system call code -- r2
//        arg1 -- r4
//        arg2 -- r5
//        arg3 -- r6
//        arg4 -- r7
//
//    The result of the system call, if any, must be put back into r2. 
//
// And don't forget to increment the pc before returning. (Or else you'll
// loop making the same system call forever!
//
//    "which" is the kind of exception.  The list of possible exceptions 
//    are in machine.h.
//----------------------------------------------------------------------
int info = NULL;
bool valid;
char **tokenname = new char*[5];
int CDcounter = 0;
bool flag=true;
char *file;
bool loc = false;
const int ROOT = 1;
bool flagslash = false;
char **saveDirName = new char*[1];

std::vector<int> CDList;

/*!Variable for ls or ls -l */
Thread* getID(int toGet)    // Goes through the list of active threads and returns one linked with the passed-in ID.
{
    Thread * tempThread = NULL;
    Thread * toReturn = NULL;
    bool found = false;
    int size = activeThreads->getSize();
    for(int i = 0; i < size; i++)
    {
        tempThread = (Thread*)activeThreads->Remove();    // Pop the top thread off.
        if (tempThread->getID() == toGet)    // If it's what we're looking for...
        {
            toReturn = tempThread;
            found = true;    // Trip the flag variable, and store the pointer of the thread.
        }
        activeThreads->Append(tempThread);    // Put it back onto the active list.
    }
    if (!found)
        return NULL;
    else return toReturn;
}
    
void processCreator(int arg)    // Used when a process first actually runs, not when it is created.
 {
    currentThread->space->InitRegisters();        // set the initial register values
    currentThread->space->RestoreState();        // load page table register
    
    if (threadToBeDestroyed != NULL){
        delete threadToBeDestroyed;
        threadToBeDestroyed = NULL;
    }

    machine->Run();            // jump to the user progam
    ASSERT(FALSE);            // machine->Run never returns;
 }

void
ExceptionHandler(ExceptionType which)
{
    int type = machine->ReadRegister(2);

    int arg1 = machine->ReadRegister(4);
    int arg2 = machine->ReadRegister(5);
    int arg3 = machine->ReadRegister(6);
    int Result;
    int i, j;
    char *ch = new char [500];

    switch ( which )
    {
    case NoException :
        break;
    case SyscallException :

        // for debugging, in case we are jumping into lala-land
        // Advance program counters.
        machine->registers[PrevPCReg] = machine->registers[PCReg];
        machine->registers[PCReg] = machine->registers[NextPCReg];
        machine->registers[NextPCReg] = machine->registers[NextPCReg] + 4;

        switch ( type )
        {

        case SC_Halt :
            //printf("SYSTEM CALL: Halt, called by thread %i.\n",currentThread->getID());
            DEBUG('t', "Shutdown, initiated by user program.\n");
            interrupt->Halt();
            break;

            
        case SC_Read :
            if (arg2 <= 0 || arg3 < 0){
                printf("\nRead 0 byte.\n");
            }
            Result = SRead(arg1, arg2, arg3);
            machine->WriteRegister(2, Result);
            DEBUG('t',"Read %d bytes from the open file(OpenFileId is %d)",arg2, arg3);
            break;

        case SC_Write :
            for (j = 0; ; j++) {
                if(!machine->ReadMem((arg1+j), 1, &i))
                    j=j-1;
                else{
                    ch[j] = (char) i;
                    if (ch[j] == '\0') 
                        break;
                }
            }
            if (j == 0){
                printf("\nWrite 0 byte.\n");
                // SExit(1);
            } else {
                DEBUG('t', "\nWrite %d bytes from %s to the open file(OpenFileId is %d).", arg2, ch, arg3); //printf("entering SWrite \n");
                SWrite(ch, j, arg3);
            }
            break;  
        case SC_Exec :    // Executes a user process inside another user process.
           {
                valid = true;
                //printf("SYSTEM CALL: Exec, called by thread %i.\n",currentThread->getID());

                // Retrieve the address of the filename
                int fileAddress = arg1; // retrieve argument stored in register r4
                //bool cmd = true;
                // Read file name into the kernel space
                char *filename = new char[100];
                char *command = new char[100];
                for(int m = 0; m < 100; m++) {
                    filename[m] = NULL;
                    command[m]=NULL;
                }
                // Free up allocation space and get the file name
                if(!machine->ReadMem(fileAddress,1,&j))return;
                i = 0;
                while(j != 0)
                {

                        filename[i]=(char)j;
                        fileAddress += 1;
                        i++;
                        if(!machine->ReadMem(fileAddress,1,&j))return;
                    
                }
                // Open File
                filename = strtok(filename, "\n");
                
                if (filename == NULL)
                    break;
                
                    
                if (flag==true)
                {
                      CDList.insert (CDList.begin(), 1 );
                    flag=false;
                }
                
                //printf("Filename is*%s.\n", filename);
                Parse(filename);
                command = strtok(filename, " ");
                    
                if (valid)
                    break;
                    
                OpenFile *executable = fileSystem->OpenRt(command);
                if (executable == NULL) 
                {
                    printf("Command: %s not found!\n", command);
                    delete filename;
                    break;
                }
                delete filename;
                

                // Calculate needed memory space
                AddrSpace *space;
                space = new AddrSpace(executable);
                delete executable;
                // Do we have enough space?
                if(!currentThread->killNewChild)    // If so...
                {
                    Thread* execThread = new Thread("thrad!");    // Make a new thread for the process.
                    execThread->space = space;    // Set the address space to the new space.
                    execThread->setID(threadID);    // Set the unique thread ID
                    activeThreads->Append(execThread);    // Put it on the active list.
                    machine->WriteRegister(2, threadID);    // Return the thread ID as our Exec return variable.
                    threadID++;    // Increment the total number of threads.
                    execThread->Fork(processCreator, 0);    // Fork it.
                }
                else    // If not...
                {
                    machine->WriteRegister(2, -1 * (threadID + 1));    // Return an error code
                    currentThread->killNewChild = false;    // Reset our variable
                }
                
                break;    // Get out.
                
            }
            case SC_Join :    // Join one process to another.
            {
                //printf("SYSTEM CALL: Joined, called by thread %i.\n",currentThread->getID());
                if(arg1 < 0)    // If the thread was not properly created...
                {
                    //printf("ERROR: Trying to join process %i to process %i, which was not created successfully! Process %i continuing normally.\n", currentThread->getID(), -arg1, currentThread->getID());    // Return an error message, continue as normal.
                    break;
                }
                
                if(getID(arg1) != NULL)    // If the thread exists...
                {
                    if(!currentThread->isJoined)    // And it's not already joined...
                    {
                        //printf("Joining process %i with process %i.  Thread %i now shutting down.\n", getID(arg1)->getID(), currentThread->getID(), currentThread->getID());    // Inform the user.
                        getID(arg1)->setParent(currentThread);    // Set the process' parent to the current thread.
                        currentThread->isJoined = true;    // Let the parent know it has a child
                        (void) interrupt->SetLevel(IntOff);    // Disable interrupts for Sleep();
                        currentThread->Sleep();    // Put the current thread to sleep.
                        break;
                    }
                    else{    // We've got an error message.
                        //printf("ERROR: Trying to join prargsocess %i, which is already joined! Continuing normally.", currentThread->getID());
                        break;
                        }
                }
                //else printf("ERROR: Trying to a join process %i to nonexistant process %i! Process %i continuing normally.\n", currentThread->getID(), -arg1, currentThread->getID());    // Error message if the thread we're trying to join to doesn't exist for some reason.
                break;
            }
            case SC_Exit :    // Exit a process.
            {
                //printf("SYSTEM CALL: Exit, called by thread %i.\n",currentThread->getID());
                /*if(arg1 == 0)    // Did we exit properly?  If not, show an error message.
                    printf("Process %i exited normally!\n", currentThread->getID());
                else
                    printf("ERROR: Process %i exited abnormally!\n", currentThread->getID());
                */
                if(currentThread->space)    // Delete the used memory from the process.
                    delete currentThread->space;
                currentThread->Finish();    // Delete the thread.

                break;
            }
           case SC_Yield :    // Yield to a new process.
           {
               //printf("SYSTEM CALL: Yield, called by thread %i.\n",currentThread->getID());

               //Save the registers and yield CPU control.
               currentThread->space->SaveState();
               currentThread->Yield();
               //When the thread comes back, restore its registers.
               currentThread->space->RestoreState();

               break;
            }

    case SC_Create:
        {
        //printf("SYSTEM CALL: CREATE, called by thread %i.\n",currentThread->getID());
        int fileAddress = arg1; // retrieve argument stored in register r4

        // Read file name into the kernel space
        char *filename = new char[100];
                
        for(int m = 0; m < 100; m++)
        filename[m] = NULL;

        // Free up allocation space and get the file name
        if(!machine->ReadMem(fileAddress,1,&j))return;
        i = 0;

        while(j != 0)
        {
            filename[i]=(char)j;
            fileAddress += 1;
            i++;
        if(!machine->ReadMem(fileAddress,1,&j))return;
        }
        fileSystem->Create(filename, arg2);
        printf("arg1 = %s arg2 = %d \n", filename, arg2);
    
        break;
        }

    case SC_Open:
    {
        //printf("SYSTEM CALL: OPEN, called by thread %i.\n",currentThread->getID());
//stuff that reads out of arg1 and makes it a char * thing
        int fileAddress = arg1; // retrieve argument stored in register r4
        // Read file name into the kernel space
        char *filename = new char[100];
            
        for(int m = 0; m < 100; m++)
        filename[m] = NULL;

        // Free up allocation space and get the file name
        if(!machine->ReadMem(fileAddress,1,&j))return;
        i = 0;

        while(j != 0)
        {
            filename[i]=(char)j;
            fileAddress += 1;
            i++;
        if(!machine->ReadMem(fileAddress,1,&j))return;
        }
//------------------------------------------------------------------end of char* thing which is filename
        fileYname * openFile = new fileYname;
        openFile->name = filename;
        openFile->file = fileSystem->Open(filename);
        openFile->id = ofcount++;
        oflist->Append(openFile);
        break;
    }
    case SC_Close:
    {
        //printf("SYSTEM CALL: CLOSE, called by thread %i.\n",currentThread->getID());
        if(oflist->getSize() == 0)
        {
            printf("No open files exist!!!! \n");
        }
        for(int k = oflist->getSize(); k > 0; k--)
        {
            fileYname * rfile = ((fileYname *) oflist->Remove());
            if(rfile->id == arg1)
            {
                //printf("closing open file : %s \n", rfile->name);
                delete rfile;    //close the file via openfile destructor!!!!
                break;
            }
            else
            {
                //printf("not closing open file : %s \n", rfile->name);
                oflist->Append(rfile);    //this is not the file, put it back!!!!
            }
        }
    // delete filename;
        break;
    }
           default :
           //Unprogrammed system calls end up here
              // printf("SYSTEM CALL: Unknown, called by thread %i.\n",currentThread->getID());
               break;
           }         // Advance program counters, ends syscall switch
           break;

    case ReadOnlyException :
        printf("ERROR: ReadOnlyException, called by thread %i.\n",currentThread->getID());
        if (currentThread->getName() == "main")
            ASSERT(FALSE);  //Not the way of handling an exception.
        if(currentThread->space)    // Delete the used memory from the process.
            delete currentThread->space;
        currentThread->Finish();    // Delete the thread.
        break;
    case BusErrorException :
        printf("ERROR: BusErrorException, called by thread %i.\n",currentThread->getID());
        if (currentThread->getName() == "main")
            ASSERT(FALSE);  //Not the way of handling an exception.
        if(currentThread->space)    // Delete the used memory from the process.
            delete currentThread->space;
        currentThread->Finish();    // Delete the thread.
        break;
    case AddressErrorException :
        printf("ERROR: AddressErrorException, called by thread %i.\n",currentThread->getID());
        if (currentThread->getName() == "main")
            ASSERT(FALSE);  //Not the way of handling an exception.
        if(currentThread->space)    // Delete the used memory from the process.
            delete currentThread->space;
        currentThread->Finish();    // Delete the thread.
        break;
    case OverflowException :
        printf("ERROR: OverflowException, called by thread %i.\n",currentThread->getID());
        if (currentThread->getName() == "main")
            ASSERT(FALSE);  //Not the way of handling an exception.
        if(currentThread->space)    // Delete the used memory from the process.
            delete currentThread->space;
        currentThread->Finish();    // Delete the thread.
        break;
    case IllegalInstrException :
        printf("ERROR: IllegalInstrException, called by thread %i.\n",currentThread->getID());
        if (currentThread->getName() == "main")
            ASSERT(FALSE);  //Not the way of handling an exception.
        if(currentThread->space)    // Delete the used memory from the process.
            delete currentThread->space;
        currentThread->Finish();    // Delete the thread.
        break;
    case NumExceptionTypes :
        printf("ERROR: NumExceptionTypes, called by thread %i.\n",currentThread->getID());
        if (currentThread->getName() == "main")
            ASSERT(FALSE);  //Not the way of handling an exception.
        if(currentThread->space)    // Delete the used memory from the process.
            delete currentThread->space;
        currentThread->Finish();    // Delete the thread.
        break;

        default :
        //      printf("Unexpected user mode exception %d %d\n", which, type);
        //      if (currentThread->getName() == "main")
        //      ASSERT(FALSE);
        //      SExit(1);
        break;
    }
    delete [] ch;
}


static int SRead(int addr, int size, int id)  //input 0  output 1
{
    char buffer[size+10];
    int num,Result;
    //printf("In Sread \n");
    //read from keyboard, try writing your own code using console class.
    if (id == 0)
    {
        fgets(buffer, size, stdin);
        //printf("Buffer is %s.\n", buffer);
        num=strlen(buffer); //set num equal to length of the buffer
        if(num>(size+1)) {

            buffer[size+1] = '\0';
            Result = size+1;
        }
        else {
            buffer[num+1]='\0';
            Result = num + 1;
        }

        for (num=0; num<Result; num++)
        {  machine->WriteMem((addr+num), 1, (int) buffer[num]);
            if (buffer[num] == '\0')
            break; }
        return num;

    }
    //read from a unix file, later you need change to nachos file system.
    else    //read a file
    {    
        //First, find the file that we want to read from in the oflist
        fileYname * rfile;
        if(oflist->getSize() == 0)
        {
            printf("No open files exist!!!! \n");
            return -1;
        }
        for(int k = oflist->getSize(); k > 0; k--)
        {
            rfile = ((fileYname *) oflist->Remove());
            if(rfile->id == id)
            {
                //We got the file
                break;
            }
            else
            {
                //printf("not closing open file : %s \n", rfile->name);
                oflist->Append(rfile);    //this is not the file, put it back!!!!
                if(k == 1)
                {
                    printf("No file open matching id \n");
                    return -1;
                }
            }
        }
        //Now that rfile has the file we want to read, we shall commence reading
        //Not so confident about this part
        for(num=0;num<size;num++){
            rfile->file->Read(&buffer[num],1);
            machine->WriteMem((addr+num), 1, (int) buffer[num]);
            if(buffer[num]=='\n') break;
        }
        oflist->Append(rfile);    //put it back cuz it still open
        return num;        //returns the number of bytes read
    }
}



static void SWrite(char *buffer, int size, int id)
{
    //int * addr;
    fileYname * rfile;
    //write to terminal, try writting your own code using console class.
    //printf("inSWrite before if id == 1 id = %d\n" , id);
    if (id == 1)
    printf("%s", buffer);
    //write to a unix file, later you need change to nachos file system.
    if (id >= 2)
    {
        //printf("inSWrite after if id >= 2 \n");
        //First, find the file that we want to read from in the oflist

        if(oflist->getSize() == 0)
        {
            printf("No open files exist!!!! ahhhh\n");
            return;
        }
        for(int k = oflist->getSize(); k > 0; k--)
        {
            rfile = ((fileYname *) oflist->Remove());
            if(rfile->id == id)
            {
                //We got the file
                break;
            }
            else
            {
                //printf("not closing open file : %s \n", rfile->name);
                oflist->Append(rfile);    //this is not the file, put it back!!!!
                if(k == 1)
                {
                    printf("No file open matching id \n");
                    return;
                }
            }
        }
        //Now that we have the file, we can write to it
        rfile->file->Write(buffer,size);
        oflist->Append(rfile);    //put it back cuz it still open
    }
}

int Locate(char* path)
{
    int dirCount = 0;
    int sizeBytes;
    char* last = strrchr(path, 47); //Find last occurance of "/"
    char* end = strchr(path, 0); //Find the end of line char
    char* first = strchr(path, 47);
    int sector;
    int prev;
    char *dir = strtok(path, "/");
    if (first == &path[0])
    {
        fileSystem->currentdir = ROOT;    
    }
    file = ++last;
        while ((int)dir != 0)
        {
            if (strcmp(".", dir) == 0)
            {
                prev = fileSystem->currentdir;
                info = 1;
            }
            else if (strcmp("..", dir) == 0)
            {
                info = 2;
                prev = fileSystem->currentdir;
                Change_dir();
            }
            else
            {
                prev = fileSystem->currentdir;
                info = 3;
                //Change_dir();
            }
            if (dir+2 == file) //!So dir will hold the previous directory and not the file
                break;
            dir = strtok(NULL, "/");
        }
        //printf("Dir is %s \n", dir);

                OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
                sizeBytes = currentopendir->Length();
        
                //fetches whatever is in the current directory
                Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
                directory->FetchFrom(currentopendir);
                if (!loc) {
                    sector = directory->Find(file);//finds the sector of the current dir
                    return sector; 
                }
                else
                {
                    //printf("here \n");
                    return prev; //return directory that you want to copy to
                }

}

void InnerParse(char *stri)
{    
    vector<int> DList(CDList);
    vector<int> FList(CDList);
    vector<int>::iterator Iter;
        
    int dirArgCount=1;
    bool flagerror = false;
    
    fileSystem->currentdir = CDList.back();
    
    for (int j = 0; j<strlen(stri); j++)
    {
        if (stri[j]=='/')
        {
        dirArgCount++;
        }
    }

    if(flagslash == true)
        {
        dirArgCount--;
        }
    
    if ((dirArgCount!=1)||(flagslash == true))
    {
        char **tokendirname = new char*[dirArgCount];
        char *tokendirch = NULL;
          int i;
      
          int dircount=0;
          int sizeBytes;
          
          for (i =0;i<dirArgCount;i++)
              tokendirname[i]=NULL;
      
          tokendirch = strtok (stri,"/");
      
          while (tokendirch != NULL && dircount<dirArgCount)
          {
                tokendirname[dircount]= tokendirch;
                tokendirch = strtok (NULL, "/");
                dircount++;
          }
      
          if (strcmp(tokendirname[0], "..") == 0)
        {
            DList.pop_back();
            fileSystem->currentdir = CDList.back();
            CDList.clear();
            for (Iter = DList.begin(); Iter < DList.end();Iter++)
            {    
                OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
                sizeBytes = currentopendir->Length();
    
                //fetches whatever is in the current directory
                Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
                directory->FetchFrom(currentopendir);
        
                fileSystem->currentdir = *Iter;
                
                CDList.push_back(*Iter);
                
                delete directory;
                delete currentopendir;    
            }
        }
        else if (strcmp(tokendirname[0], ".") == 0)
        {
            fileSystem->currentdir = CDList.back();
        }
        else if (flagslash == true)
        {
            CDList.clear();
            CDList.push_back(1);
            fileSystem->currentdir = 1;
        }
        
    int sector;
    if (flagslash == true)
        i=0;
    else 
        i=1;
                
    for (i; i<dirArgCount; i++)
    {
        BitMap* dirmap = new BitMap(NumSectors);
            OpenFile* dirmapopen = new OpenFile(2);
            dirmap->FetchFrom(dirmapopen);
    
        OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
        sizeBytes = currentopendir->Length();
    
        //fetches whatever is in the current directory
        Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
        directory->FetchFrom(currentopendir);
        
        sector = directory->Find(tokendirname[i]);
    
        if(sector !=-1 && dirmap->Test(sector))
        {
            fileSystem->currentdir = sector; 
            CDList.push_back(sector);        
        }
        else
        {
            printf("\nCould not find the directory: %s\n", tokendirname[i]);
            flagerror = true;
            break;
        }
        
        
        delete directory;
        delete currentopendir;    
        delete dirmap;
        delete dirmapopen;        
    }
    }
    flagslash=false;
    if (flagerror == true)
    {
    CDList.clear();
    for (Iter = FList.begin();Iter <FList.end();Iter++)
        CDList.push_back(*Iter);
    fileSystem->currentdir = CDList.back();        
    }
}

void Parse(char *str)
{
    if (str == NULL)
    {
    }
    else
    {
    
    char *tokench = NULL;
      
      
      int i;
      int argcount=0;
          
      for (i =0;i<5;i++)
          tokenname[i]=NULL;
      
      tokench = strtok (str," ");
      
      while (tokench != NULL && argcount<5)
      {
            tokenname[argcount]= tokench;
            tokench = strtok (NULL, " ");
            argcount++;
      }
      
    //the comparision of command with tokenname[0] which holds the command name
    if (strcmp(tokenname[0],"ls") == 0)
    {
        /*!Returns pointer to characters after and including the first hyphen.*/
        if (argcount==1)
        {
            Ls();
        }
        else if (argcount==2)
        {
            if (strcmp(tokenname[1], "-l") == 0)
            {
                info = 1;
                Ls();
            }
            else 
            {
                printf("Command unrecognized. \n");
                valid = false;
            }
        }
        else
        {
            printf("Command unrecognized. \n");
            valid = false;
        }
        

    }
    else if (strcmp(tokenname[0], "pwd") == 0)
    {
        Pwd();
    }
    else if (strcmp(tokenname[0], "cat") == 0)
    {
        //printf("Command is cat. \n");
        if (argcount == 5)
        {
            if (strcmp(tokenname[3], ">") == 0)    
                Cat(true);
            else
            {
                printf("Invalid syntax for cat.\n");
                valid = false;
            }
        }
        else if (argcount == 2)
        {
            Cat(false);
        }
        else
        {
            printf("Invalid number of arguments. \n");
            valid = false;
        }
    }
    else if (strcmp(tokenname[0], "mkdir") == 0)
    {
        if (argcount == 1)
        {
            printf("Less Arguments! \n");
            valid = false;
        }
        else if (argcount>=2)
        {    int saveSect = fileSystem->currentdir;
            char *stri = tokenname[1];
                
            if (stri[0] =='/')
                flagslash = true;
                
            Make_dir();
            fileSystem->currentdir = saveSect;
        }
        else 
        {
            printf("Command unrecognized. \n");
            valid = false;
        }

    }
    else if (strcmp(tokenname[0], "rmdir") == 0)
    { 
        if (argcount == 1)
        {
            printf("Less Arguments! \n");
            valid = false;
        }
        else if (argcount>=2)
        {    
            Remove_dir();
        }
        else 
        {
            printf("Command unrecognized. \n");
            valid = false;
        }
        
    }
    else if (strcmp(tokenname[0], "rm") == 0)
    {    
        if (argcount == 1)
        {
            printf("Less Arguments! \n");
            valid = false;
        }
        else if (argcount>=2)
        {    
            Remove();
        }
        else 
        {
            printf("Command unrecognized. \n");
            valid = false;
        }
    }
    else if (strcmp(tokenname[0], "mv") == 0)
    {
        if (strcmp(tokenname[0], "mv") == 0 && argcount < 2)
        {
            printf("Invalid number of arguments. \n");
            valid = false;
        }
    }
    else if (strcmp(tokenname[0], "cp") == 0)
    {    
        if (strcmp(tokenname[0], "cp") == 0 && argcount < 3)
        {    
            printf("Invalid number of arguments. \n");
            valid = false;
        }
        else
        {
            Copy();
        }
        
    }
    else if (strcmp(tokenname[0], "cd") == 0)
    {
        if (argcount == 1)
            {
                printf("Less Arguments. \n");
                valid = false;
            }
        else if (argcount>=2)
        {    
            if (strcmp(tokenname[1], ".") == 0)
            {    
                info = 1;
                Change_dir();
            }
            else if (strcmp(tokenname[1], "..") == 0)
            {    
            
                fileSystem->currentdir = 1; 
                info = 2;
                Change_dir();
            }
            else if (strcmp(tokenname[1], "/") == 0)
            {    
                fileSystem->currentdir = 1; 
                CDList.erase(CDList.begin(), CDList.end());
                CDList.insert (CDList.begin(), 1 );
                info = 2;
            }
            else if ((strcmp(tokenname[1], "..") != 0) ||(strcmp(tokenname[1], ".") != 0)|| (strcmp(tokenname[1], "/") != 0))
            {
                int dirArgCount1=0;
                char *stri = tokenname[1];
                
                if (stri[0] =='/')
                        flagslash = true;
                    
                for (int j = 0; j<strlen(stri); j++)
                {
                    if (stri[j]=='/')
                        dirArgCount1++;
                }
            
                if (dirArgCount1 ==0)
                {
                    info = 3;
                    Change_dir();
                }
                else 
                {
                    InnerParse(tokenname[1]);
                }
            
            }
        }    
        else 
        {
            printf("\nCommand unrecognized. \n");
            valid = false;
        }
    }
                
    
    else 
    {
        valid = false;
    }
}
}

void Pwd()
{
 vector<int>::iterator Iter;
 int savesector = fileSystem->currentdir;
 int sizeBytes = 0; 
 
 if (CDList.size()==1)
        {
            printf("/\n");
        }
 else
{
fileSystem->currentdir = 1;
for (Iter = CDList.begin(); Iter < CDList.end();Iter++)
    {    
        
            OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
            sizeBytes = currentopendir->Length();
    
            //fetches whatever is in the current directory
            Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
            directory->FetchFrom(currentopendir);
            
            directory->PrintNameOfSector(*Iter);
            printf("/");
            
            fileSystem->currentdir = *Iter;
            
            delete directory;
            delete currentopendir;            
    }
    printf("\n");
}
    
    
    fileSystem->currentdir = savesector; 
}

void Ls()
{    
    int sizeBytes;
    
    OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
    sizeBytes = currentopendir->Length();
 
    Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
    directory->FetchFrom(currentopendir);
        
    if(info==1)
        {
        directory->ListSize();
        info = 0;
        }
     else 
         directory->List();
         
    delete directory;
    delete currentopendir;
}

// end FA98

void Make_dir()
{    printf("\nInside make dir\n");    
    
    char* stri = tokenname[1];
    
    vector<int> DList(CDList);
    vector<int> FList(CDList);
    vector<int>::iterator Iter;
        
    int dirArgCount=1;
    bool flagerror = false;
    
    fileSystem->currentdir = CDList.back();
    
    for (int j = 0; j<strlen(stri); j++)
    {
        if (stri[j]=='/')
        {
        dirArgCount++;
        }
    }
    printf("\n%s\n", stri);

    if(flagslash == true)
        {
        dirArgCount--;
        }
    
    if ((dirArgCount!=1)||(flagslash == true))
    {
        char **tokendirname = new char*[dirArgCount];
        char *tokendirch = NULL;
          int i;
      
          int dircount=0;
          int sizeBytes;
          int sector;
          
          for (i =0;i<dirArgCount;i++)
              tokendirname[i]=NULL;
      
          tokendirch = strtok (stri,"/");
      
          while (tokendirch != NULL && dircount<dirArgCount)
          {
                tokendirname[dircount]= tokendirch;
                tokendirch = strtok (NULL, "/");
                dircount++;
          }
      
          if (strcmp(tokendirname[0], "..") == 0)
        {
            DList.pop_back();
            fileSystem->currentdir = DList.back();    
            
        }
        else if (strcmp(tokendirname[0], ".") == 0)
        {
            fileSystem->currentdir = CDList.back();
        }
        else if (flagslash == true)
        {
            CDList.clear();
            CDList.push_back(1);
            fileSystem->currentdir = 1;
        }
        
    if (flagslash == true)
        i=0;
    else 
        i=1;
                
    for (i; i<dirArgCount-1; i++)
    {
        Directory *newdirectory = new Directory(12);
            BitMap* dirmap = new BitMap(NumSectors);

            OpenFile* dirmapopen = new OpenFile(2);
            dirmap->FetchFrom(dirmapopen);
    
        if (!fileSystem->Create(tokendirname[dirArgCount+1], 12* sizeof(DirectoryEntry)))
            {
                printf("\nCould not create directory! Wrong path or filename\n");
                flagerror = true;
            }
        else
        {
            // the current directory stores the sector number that contains the fileheader
            OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
            sizeBytes = currentopendir->Length(); //length returns the size of the directory table.
    
            Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
            directory->FetchFrom(currentopendir);
        
            sector = directory->Find(tokendirname[dirArgCount+1]);//finds the sector of the current dir
            printf("MKDIR sector : %d\n",sector);
            dirmap->Mark(sector);//marks that sector as a directory
    
            OpenFile* opennewdir = new OpenFile(sector); //opening the newdirectory fileheader 
            newdirectory->WriteBack(opennewdir);//writing the directory to the sector that is pointed by the opened file header 
            dirmap->WriteBack(dirmapopen); //updating the dirmap in the hard disk.
        
            printf("\nDirectory: %s Created\n", tokendirname[dirArgCount+1]); 
        
            delete directory;
            delete dirmapopen;
            delete currentopendir;
            delete opennewdir;
        }
    
        delete newdirectory;
        delete dirmap;
    }
    
    flagslash=false;
    if (flagerror == true)
    {
        CDList.clear();
        for (Iter = FList.begin();Iter <FList.end();Iter++)
        CDList.push_back(*Iter);
        fileSystem->currentdir = CDList.back();        
    }
}
    
    

    
    
}

void Remove_dir()
{    printf("\nInside remove dir\n");    

    BitMap* dirmap = new BitMap(NumSectors);
    
    //opening the current directory for fetch and write
    OpenFile* dirmapopen = new OpenFile(2);
    //fetching from the disk sector
    dirmap->FetchFrom(dirmapopen);
        
    int sizeBytes;
    int sector;
    
    //opens the current directory    
    OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
    sizeBytes = currentopendir->Length();
 
     //fetches whatever is in the current directory
    Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
    directory->FetchFrom(currentopendir);
    
    sector = directory->Find(tokenname[1]);//finds the sector of the current dir
    
    if (dirmap->Test(sector)== 1)
    {
        if(fileSystem->Remove(tokenname[1]))
            printf("\nDirectory: %s Removed\n", tokenname[1]);
        else
            printf("\nCould not find directory: %s\n", tokenname[1]);
    }
    else
        printf("\nCould not find directory: %s\n", tokenname[1]);
    delete directory;
    delete currentopendir;    
}

void Change_dir()
{    
    //printf("\nInside change dir\n");    
    if (info ==1)
    {
        info =0;
    }
    else if (info ==2)
    {    
        vector<int>::iterator Iter;
         int sizeBytes;
         
         if (CDList.size()==1)
        {
            printf("\nYou are in the root. Cannot go behind root.\n");
        }
        else
        {
            CDList.pop_back();

            fileSystem->currentdir = 1;
            for (Iter = CDList.begin(); Iter < CDList.end();Iter++)
            {    
        
                OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
                sizeBytes = currentopendir->Length();
    
                //fetches whatever is in the current directory
                Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
                directory->FetchFrom(currentopendir);
        
                fileSystem->currentdir = *Iter;
                
                delete directory;
                delete currentopendir;            
            }
        }
        info =0;
    }
    else if (info ==3)
    {    
        int sizeBytes;
        int sector;
    
        BitMap* dirmap = new BitMap(NumSectors);
            OpenFile* dirmapopen = new OpenFile(2);
            dirmap->FetchFrom(dirmapopen);
    
        OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
        sizeBytes = currentopendir->Length();
    
        //fetches whatever is in the current directory
        Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
        directory->FetchFrom(currentopendir);
    
        sector = directory->Find(tokenname[1]);
    
        if(sector !=-1 && dirmap->Test(sector))
        {
            fileSystem->currentdir = sector; 
            CDList.push_back(sector);        
        }
        else
        {
            printf("\nCould not find the directory: %s\n", tokenname[1]);
        }
            
        delete directory;
        delete currentopendir;    
        delete dirmap;
        delete dirmapopen;
        info =0;
    }

}

void Remove()
{    printf("\nInside Remove file function\n");    
    
    BitMap* dirmap = new BitMap(NumSectors);
    
    //opening the current directory for fetch and write
    OpenFile* dirmapopen = new OpenFile(2);
    //fetching from the disk sector
    dirmap->FetchFrom(dirmapopen);
        
    int sizeBytes;
    int sector;
    
    //opens the current directory    
    OpenFile* currentopendir = new OpenFile(fileSystem->currentdir); 
    sizeBytes = currentopendir->Length();
 
     //fetches whatever is in the current directory
    Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
    directory->FetchFrom(currentopendir);
    
    sector = directory->Find(tokenname[1]);//finds the sector of the current dir
    
    if (dirmap->Test(sector)== 0)
    {
        if(fileSystem->Remove(tokenname[1]))
            printf("\nFile: %s Removed\n", tokenname[1]);
        else
            printf("\nCould not find file: %s in the directory\n", tokenname[1]);
    }
    else
        printf("\nCould not find file: %s in the directory\n", tokenname[1]);
        
    delete directory;
    delete currentopendir;    
}


void Copy()
{ 
    int start = fileSystem->currentdir;
    int sector1;
    int sector2;
    loc = false;
    
    BitMap* dirmap = new BitMap(NumSectors);
    OpenFile* dirmapopen = new OpenFile(2);
    dirmap->FetchFrom(dirmapopen);
    
    sector1 = Locate(tokenname[1]);
    printf("Sector of file is %d \n", sector1);
    loc = true;
    bool created;
    sector2 = Locate(tokenname[2]);
    printf("Sector of directory is %d \n", sector2);
    if (sector1 == -1 || sector2 == -1)
        printf("File not found. \n");
    else
    {
        //Check if file is a directory or not
        int sizeBytes;
        int sizeFile;
    
    //opens the current directory    
        OpenFile* currentopendir = new OpenFile(sector2); 
        sizeBytes = currentopendir->Length();

    //gets file
        OpenFile* target = new OpenFile(sector1);
        sizeFile = target->Length();
     //fetches whatever is in the current directory
        Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
        directory->FetchFrom(currentopendir);
        created = fileSystem->Create(file, sizeFile);
            
        if (created == false)
            printf("Something went wrong. \n");
        else
        {
            printf("Attempting copy. \n");
            char *buffer = new char[sizeBytes];
            OpenFile* dest = fileSystem->Open(file);
            for (int i=0; i<sizeBytes; i++)
            {
                target->Read(buffer, 1);
                dest->Write(buffer, 1);
                        
            } 
            printf("File created . \n");
        }
    }
    fileSystem->currentdir = start;
}

void Cat(bool isCombine)
{
    char* fileBuf; 
    
    BitMap * dirmap = new BitMap(NumSectors);
    OpenFile * fTwoSrc, * fOneSrc, * fNewSrc;

    //opening the current directory for fetch and write
    OpenFile* dirmapopen = new OpenFile(2);
    //fetching from the disk sector
    dirmap->FetchFrom(dirmapopen);
    int sizeBytes;
    int sectorOne, sectorTwo, sectorNov;
    int oneSize, twoSize, novSize, combSize;
    int whichFile;
    int written;    
    bool removeOK = true;


    if (isCombine)
    {

        if (strcmp(tokenname[4],tokenname[1]) == 0)
        {
            //printf ("Destination will expand File 1.\n");
            whichFile = 1;
        }
        else if (strcmp(tokenname[4],tokenname[2]) == 0)
        {
            //printf ("Destination will expand File 2.\n");
            whichFile = 2;
        }
        else
        {
            printf ("cat failed: Destination is not one of the two passed files.\n");
            whichFile = 4;
            return; //expansion for files
        }
    }
    //opens the current directory    
    OpenFile* currentopendir = new OpenFile(fileSystem->currentdir);
    sizeBytes = currentopendir->Length();

    //fetches whatever is in the current directory
    Directory *directory = new Directory((sizeBytes/sizeof(DirectoryEntry)));
    directory->FetchFrom(currentopendir);



    sectorOne = directory->Find(tokenname[1]);//finds the sector of the first file

    //printf("testPre - sector one is %d\n", sectorOne);
    if (isCombine)
    {
        sectorTwo = directory->Find(tokenname[2]);//'' second file

        //printf("testPre - sector two is %d\n", sectorTwo);
    
        //make sure file 2 isn't a directory
        if (dirmap->Test(sectorTwo) == 0 && dirmap->Test(sectorOne) == 0)
        {

            fOneSrc = new OpenFile(sectorOne);
            fTwoSrc = new OpenFile(sectorTwo);

            oneSize = fOneSrc->Length();
            twoSize = fTwoSrc->Length();
            combSize = twoSize + oneSize;

            if (whichFile == 1 ||  whichFile == 2)
            {
                removeOK = false;
                if (whichFile == 1)
                {
                    fileBuf = new char[oneSize];
                    written = fOneSrc->Read(fileBuf, sizeBytes);
                    delete fOneSrc;
                }
                else if (whichFile == 2)
                {
                    fileBuf = new char[twoSize];
                    written = fTwoSrc->Read(fileBuf, sizeBytes);
                    delete fTwoSrc;
                }
                        if (!fileSystem->Remove(tokenname[whichFile]))
                {
                    printf("\nCouldn't re-init File %d for expansion!\n", whichFile);
                    ASSERT(FALSE);
                }
                else
                    removeOK = true;
            }
            else
            {
                fileBuf = new char[oneSize];
                written = fOneSrc->Read(fileBuf, sizeBytes);
            }
            if(removeOK)
                    {
                if(fileSystem->Create(tokenname[whichFile], combSize))
                {
                    sectorNov = directory->Find(tokenname[whichFile]);
                    fNewSrc = new OpenFile(sectorNov);
                    
                    if (whichFile == 1 ||  whichFile == 2)
                    {
                        //printf("Expanding File %d.\n", whichFile);
                        if(whichFile == 1)
                        {
                            written = fNewSrc->Write(fileBuf, oneSize);
                            delete fileBuf;
                            fileBuf = new char[twoSize];
                            written = fTwoSrc->Read(fileBuf, twoSize);
                            written = fNewSrc->Write(fileBuf, twoSize);
                        }
                        else
                        {
                            written = fNewSrc->Write(fileBuf, twoSize);
                            delete fileBuf;
                            fileBuf = new char[oneSize];
                            written = fOneSrc->Read(fileBuf, oneSize);
                            written = fNewSrc->Write(fileBuf, oneSize);
                        }
                    }
                    else
                    {
                        //printf("pong\n");
                        written = fNewSrc->Write(fileBuf, oneSize);
                        delete fileBuf;
                        fileBuf = new char[twoSize];
                        //printf("p2ng\n");
                        written = fTwoSrc->Read(fileBuf, twoSize);
                        //printf("p3ng\n");
                        written = fNewSrc->Write(fileBuf, twoSize);
                    }
                    
                 }
                else
                {
                    //printf("pong\n");    
                    if(whichFile == 1 || whichFile == 2)
                    {        
                        if (whichFile == 1)
                            novSize = oneSize;
                        else
                            novSize = twoSize;        
                        printf("Couldn't expand File %d.\n", whichFile);
                        if(directory->Find(tokenname[whichFile]) != -1)
                        {
                            if (!fileSystem->Remove(tokenname[whichFile]))
                            {
                                printf("\nCouldn't re-init File %d for renewal!\n", whichFile);
                                ASSERT(FALSE); //if this happens we have a problem
                            } 
                        }
                        if(!fileSystem->Create(tokenname[whichFile], novSize))
                        {
                            printf("\nCouldn't recreate File %d!\n", whichFile);
                            ASSERT(FALSE); //if this happens we have a problem
                         }
                        else
                        {
                            sectorNov =  directory->Find(tokenname[whichFile]);
                            fNewSrc = new OpenFile(sectorNov);
                            written = fNewSrc->Write(fileBuf, novSize);
                        }
                    }
                    else
                    {
                        if(directory->Find(tokenname[whichFile]) != -1)
                        {    
                            printf("Removing incomplete file.\n");
                            if (!fileSystem->Remove(tokenname[whichFile]))
                            {
                                printf("\nCouldn't remove new file!\n");
                                ASSERT(FALSE);
                            } 
                        }
                    }
                }
                //delete fileBuf;
            }
            if(whichFile == 1 || whichFile == 3)
                delete fTwoSrc;
            if(whichFile == 2 || whichFile == 3)
                delete fOneSrc;
            delete fNewSrc;
            delete fileBuf;

        }
        else
            printf("sector %d is an existing directory, not a file.\n", sectorTwo);

        delete currentopendir;
        delete dirmapopen;
        delete dirmap;
        delete directory;
        //printf("cat function complete\n");
    }
    
    else
    {
        //printf("Solo printout version.\n");
        OpenFile * fSoloSrc = new OpenFile(sectorOne);
        int soloLen = fSoloSrc->Length();
         char * soloBuf = new char[soloLen];
        printf("Printing contents of %s.\n\n", tokenname[1]);
    
        int fileserv = fSoloSrc->Read(soloBuf, soloLen);
    
        for(int j = 0; j < soloLen; j++)
        {
            printf("%c", soloBuf[j]);
        }
        //printf("\n cat function(solo) complete. \n");
    
        delete fSoloSrc;
        delete soloBuf;
        delete currentopendir;
        delete dirmapopen;
        delete dirmap;
        delete directory;
    }
}

